#ifndef _FUNCTIONS_H_
#define _FUNCTIONS_H_

#include <CImg.h>
#include <iostream>
#include <fstream>
#include <math.h>
#include <complex>
#include <map>
#include <vector>
#include <bitset>
#include <utility> // make_pair

/*
Definicion de Parametros

Aqui los importantes a tocar son threshold y compresionScale
30 y 3 son los valores que mejor andan visualmente.
*/
/*
#define blockSize 8 			// tamanio de cada subimagen
#define threshold 40			// umbral de energia, menor a 100 o me matas!, entre 30 o 80 ideal
#define pi 3.14159
#define compressionScale 3		// mientras mas grande este valor, mas comprimido
#define charsPerBlock 1			// caracteres por subimagen
#define nBitsCode 5				// cantidad de bits p/representar 1 caracter
*/

#define pi 3.14159

using namespace std;
using namespace cimg_library;

void toBinary(bool* bin, int val);

void LSB(vector<float>& vZig,char* pChar, int p);

void LSBInv(vector<float>& vZig, vector<char>& pChar);

bool th(float val);

int findIndex(char c);

int toInt(bool* bin, int size);

void loadConfig();

char* loadText(const char* path);

bool blockMultiple (CImg<float>& img);

void zigZag(CImg<float>& dctBlock,vector<float>& vZig,bool inverse=false);

void makeBase(CImgList<>& bases);

void encriptyon(char* pChar);

template<class T>
float norm2(CImg<T>& block){
	float norm = 0.;
	cimg_forXY(block,i,j){
		if(i||j) norm += pow(block(i,j),2);
	}
	return sqrt(norm);
}

template<class T>
CImg<T> DCT(const CImg<T>& f,CImgList<>& bases, int blockSize){
	CImg<T> F(blockSize,blockSize);
	float aux, alfaU, alfaV;
	cimg_forXY(F,u,v){
		aux = 0.;
		alfaU = (!u) ? sqrt(1./(float)blockSize) : sqrt(2./(float)blockSize);
		alfaV = (!v) ? sqrt(1./(float)blockSize) : sqrt(2./(float)blockSize);
		cimg_forXY(f,x,y) aux += f(x,y) * bases[u*blockSize+v](x,y);
		aux = aux * alfaU * alfaV;
		F(u,v) = aux;
	}
	//(F.get_normalize(0.,255.)).display(0,0);
	return F;
}

template<class T>
CImg<T> IDCT(const CImg<T>& F,CImgList<>& bases, int blockSize){
	CImg<T> f(blockSize,blockSize);
	float aux, alfaU, alfaV;
	cimg_forXY(f,x,y){
		aux = 0.;
		cimg_forXY(F,u,v){
			alfaU = (!u) ? sqrt(1./(float)blockSize) : sqrt(2./(float)blockSize);
			alfaV = (!v) ? sqrt(1./(float)blockSize) : sqrt(2./(float)blockSize);
		 	aux += alfaU * alfaV * F(u,v) * bases[u*blockSize+v](x,y);
		}
		f(x,y) = aux;
	}
	//(F.get_normalize(0.,255.)).display(0,0);
	return f;
}

#endif

